
/*                          UX-Framework                               
 *                                                                 
 *  iZE Co.,Ltd. Copyright 2009 All rights reserved.          
 *  This file is distributed under the terms of the GNU Lesser 
 *  General Public License, described in file LICENSE.                                     
 */
package jp.ize.ux.components;

// {{{ imports
import jp.ize.ux.UXObject;
import jp.ize.ux.UXController;
import jp.ize.ux.UXInteraction;
import jp.ize.ux.components.UXComponent;
import jp.ize.ux.components.UXButton;
import jp.ize.ux.components.UXComponentResource;
import jp.ize.ux.components.themes.basic.UXScrollBarResource;
import jp.ize.ux.interactions.UXGeneralInteraction;
import jp.ize.ux.events.UXMouseEvent;
import jp.ize.ux.utils.UXRange;
import jp.ize.ux.states.UXBasicState;
import jp.ize.ux.acts.Act;
import jp.ize.ux.geom.UXSize;
import flash.geom.Rectangle;
import flash.geom.Point;
// }}}
// {{{ enum UXScrollBarDirection
enum UXScrollBarDirection
{
	/** 水平方向を表すバリアントです。 */
	HORIZONTAL;
	/** 鉛直方向を表すバリアントです。 */
	VERTICAL;
}
// }}}
// {{{ class UXScrollBarAct extends Act
/**
 * UXScrollBarAct クラス<br>
 * UXScrollBarのデフォルトアクションです。
 */
class UXScrollBarAct extends Act
{
	// {{{ public function new()
	/**
	 * コンストラクタです。<br>
	 */
	public function new()
	{
		super();
	}
	// }}}
	// {{{ public function scroll() : UXScrollBarState -> Void
	/**
	 * スクロールした時のデフォルトアクションです。
	 */
	public function scroll() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
			s.setScrollPosition( s.delta );
		}
	}
	// }}}
	// {{{ public function stepScroll() : UXScrollBarState -> Void
	/**
	 * スクロールした時のデフォルトアクションです。
	 */
	public function stepScroll() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
			s.addScrollPosition( s.delta*s.step );
		}
	}
	// }}}
	// {{{ public function pageScroll() : UXScrollBarState -> Void
	/**
	 * スクロールした時のデフォルトアクションです。
	 */
	public function pageScroll() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
			s.addScrollPosition( s.delta*s.pageSize );
		}
	}
	// }}}
	// {{{ public function wheelScroll() : UXScrollBarState -> Void
	/**
	 * スクロールした時のデフォルトアクションです。
	 */
	public function wheelScroll() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
			s.addScrollPosition( -s.mouse.delta*s.step );
		}
	}
	// }}}
	// {{{ public function highlight() : UXScrollBarState -> Void
	/**
	 * ハイライトした時のデフォルトアクションです。
	 */
	public function highlight() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
		}
	}
	// }}}
	// {{{ public function unhighlight() : UXScrollBarState -> Void
	/**
	 * ボタンのハイライトを解除した時のデフォルトアクションです。
	 */
	public function unhighlight() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
		}
	}
	// }}}
	// {{{ public function focus() : UXScrollBarState -> Void
	/**
	 * ボタンがフォーカスされた時のデフォルトアクションです。
	 */
	public function focus() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
		}
	}
	// }}}
	// {{{ public function unfocus() : UXScrollBarState -> Void
	/**
	 * ボタンのフォーカスが解除された時のデフォルトアクションです。
	 */
	public function unfocus() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
		}
	}
	// }}}
	// {{{ public function enable() : UXScrollBarState -> Void
	/**
	 * 有効にした時のデフォルトアクションです。
	 */
	public function enable() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
			s.enabled = true;
			s.trac.normal();
			s.thumb.normal();
		}
	}
	// }}}
	// {{{ public function disable() : UXScrollBarState -> Void
	/**
	 * 無効にした時のデフォルトアクションです。
	 */
	public function disable() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
			s.enabled = false;
			s.trac.disabled();
			s.thumb.disabled();
		}
	}
	// }}}
	// {{{ public function show() : UXScrollBarState -> Void
	/**
	 * 表示状態になった時のデフォルトアクションです。
	 */
	public function show() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
		}
	}
	// }}}
	// {{{ public function hide() : UXScrollBarState -> Void
	/**
	 * 非表示状態になった時のデフォルトアクションです。
	 */
	public function hide() : UXScrollBarState -> Void
	{
		return function( s:UXScrollBarState ) {
		}
	}
	// }}}
}
// }}}
// {{{ class UXScrollBarState extends UXBasicState
/**
 * UXScrollBarState クラス<br>
 * UXScrollBarの現在の状態を表すオブジェクトです。<br>
 * 常にrange.min <= scrollPosition <= scrollPosition + pageSize <= range.max が成り立ちます。<br>
 */
class UXScrollBarState extends UXBasicState
{
	// {{{ properties
	// {{{ public var upArrorwResource( default, default ) : UXComponentResource;
	/**
	 * 上矢印ボタンのためのリソースです。
	 */
	public var upArrowResource( default, default ) : UXComponentResource;
	// }}}
	// {{{ public var downArrowResource( default, default ) : UXComponentResource;
	/**
	 * 下矢印ボタンのためのリソースです。
	 */
	public var downArrowResource( default, default ) : UXComponentResource;
	// }}}
	// {{{ public var size( default, default ) : UXSize;
	/**
	 * スクロールのサイズです。
	 */
	public var size( default, default ) : UXSize;
	// }}}
	// {{{ public var trac( default, default ) : UXComponentResource
	/**
	 * スクロールトラック(背景)です。
	 */
	public var trac( default, default ) : UXComponentResource;
	// }}}
	// {{{ public var thumb( default, default ) : UXComponentResource
	/**
	 * スクロールバーのサムです。
	 */
	public var thumb( default, default ) : UXComponentResource;
	// }}}
	// {{{ public var direction( default, default ) : UXScrollBarDirection
	/**
	 * スクロールが水平方向か、鉛直方向かを設定します。
	 */
	public var direction( default, default ) : UXScrollBarDirection;
	// }}}
	// {{{ public var liveDragging( default, default ) : Bool;
	/**
	 * ユーザーがスライダサムをドラッグしている間、UXScrollBarScrollInteractionが
	 * 継続的にスクロール位置が変化したというイベント送出するかどうかを示すブール値を取得または設定します。
	 */
	public var liveDragging( default, default ) : Bool;
	// }}}
	// {{{ public var range( default, default ) : UXRange;
	/**
	 * 最小値と最大値を設定します。scrollPosition は range.min から range.max-pageSize
	 * までの範囲で設定できることを注意してください。
	 */
	public var range( default, default ) : UXRange;
	// }}}
	// {{{ public var pageSize( default, default ) : Float;
	/**
	 * 1ページのサイズです。このサイズによって、サムのサイズを決定します。
	 */
	public var pageSize( default, default ) : Float;
	// }}}
	// {{{ public var step( default, default ) : Float;
	/**
	 * ホイールを使ったスクロール時のステップ数です。
	 */
	public var step( default, default ) : Float;
	// }}}
	// {{{ public var delta( default, default ) : Float;
	/**
	 * スクロール時の移動量です。
	 */
	public var delta( default, default ) : Float;
	// }}}
	// {{{ public var position( default, default ) : Float;
	/**
	 * スクロール位置の現在の値を取得または設定します。
	 */
	public var position( default, default ) : Float;
	// }}}
	// {{{ public var acts(default, null) : UXScrollBarAct
	/**
	 * デフォルトの動きです。
	 */
	public var acts(default, null) : UXScrollBarAct;
	// }}}
	// }}}
	// {{{ public function new( mysize:UXSize, dir:UXScrollBarDirection ) : Void

	public function new( mysize:UXSize, dir:UXScrollBarDirection ) : Void
	{
		super();
		this.size      = mysize;
		this.direction = dir;
		var res = new UXScrollBarResource(this,dir);
		this.trac      = res.trac;
		this.thumb     = res.thumb;
		acts = new UXScrollBarAct();
		thumb.addUXEventListener( UXMouseEvent.DOWN, onThumbMouseDown );
		thumb.addUXEventListener( UXMouseEvent.UP,   onThumbMouseUp );
		thumb.addUXEventListener( UXMouseEvent.OVER, onThumbMouseUp );
		thumb.addUXEventListener( UXMouseEvent.OUT,  onThumbMouseUp );
		trac.addUXEventListener(  UXMouseEvent.UP,   onTracMouseUp );
	}

	// }}}
	// {{{ public function onThumbMouseDown( e:Dynamic ) : Void

	public function onThumbMouseDown( e:Dynamic ) : Void
	{
		var bounds = null;
		if ( direction==HORIZONTAL ) {
			bounds = new Rectangle( 0, 0, range.max, 0 );
		} else {
			bounds = new Rectangle( 0, 0, 0, range.max );
		}
		thumb.startDrag( false, bounds );
	}

	// }}}
	// {{{ public function onThumbMouseUp( e:Dynamic ) : Void

	public function onThumbMouseUp( e:Dynamic ) : Void
	{
		thumb.stopDrag();
		if ( direction==HORIZONTAL ) {
			setScrollPosition( thumb.x );
		} else {
			setScrollPosition( thumb.y );
		}
	}

	// }}}
	// {{{ public function onTracMouseUp( e:Dynamic ) : Void

	public function onTracMouseUp( e:Dynamic ) : Void
	{
		var p1 = new Point(e.stageX,e.stageY);
		var p2 = trac.globalToLocal(p1);
		if ( direction==HORIZONTAL ) {
			setScrollPosition( p2.x - thumb.width/2 );
		} else {
			setScrollPosition( p2.y - thumb.height/2 );
		}
	}

	// }}}
	// {{{ public function setMaxScroll( val:Float ) : Void

	public function setMaxScroll( val:Float ) : Void
	{
		var max:Float = 0;
		if ( val<=0 ) val = 1;
		if ( direction==HORIZONTAL ) {
			thumb.width  = size.width/val;
			max = size.width - thumb.width;
			if ( max<0 ) max = 0;
			pageSize = size.width;
			step     = size.width/36;
		} else {
			thumb.height = size.height/val;
			max = size.height - thumb.height;
			if ( max<0 ) max = 0;
			pageSize = size.height;
			step     = size.height/36;
		}
		range = new UXRange(0,max);
	}

	// }}}
	// {{{ public function setScrollPosition( pos:Float ) : Void

	public function setScrollPosition( pos:Float ) : Void
	{
		if ( range.inValue(pos) ) {
			if ( direction==HORIZONTAL ) {
				thumb.x = pos;
			} else {
				thumb.y = pos;
			}
		} else if ( pos<=range.min ) {
			if ( direction==HORIZONTAL ) {
				thumb.x = 0;
			} else {
				thumb.y = 0;
			}
		} else if ( pos>=range.max ) {
			if ( direction==HORIZONTAL ) {
				thumb.x = size.width - thumb.width;
			} else {
				thumb.y = size.height - thumb.height;
			}
		}
		cast(target,UXScrollBar).ctrl.trigger("Scrolled");
	}

	// }}}
	// {{{ public function addScrollPosition( d:Float ) : Void

	public function addScrollPosition( d:Float ) : Void
	{
		var pos = getScrollPosition();
		setScrollPosition( pos + d );
	}

	// }}}
	// {{{ public function getScrollPosition() : Float

	public function getScrollPosition() : Float
	{
		if ( direction==HORIZONTAL ) {
			return thumb.x;
		} else {
			return thumb.y;
		}
	}

	// }}}
	// {{{ public function getScrollValue() : Float

	public function getScrollValue() : Float
	{
		return getScrollPosition() / range.max;
	}

	// }}}
	// {{{ public function refresh() : Void

	public function refresh() : Void
	{
		if ( range!=null ) {
			var v = getScrollValue();
			trac.normal();
			thumb.normal();
			setScrollPosition( v * range.max );
		}
	}

	// }}}
}
// }}}

// {{{ class UXScrollBar extends UXComponent<UXScrollBarState>
/**
 * UXScrollBarクラス<br>
 * スクロールバーの実装です。<br>
 *
 * @author		iZE Co., Ltd.<br>
 * @version		$Id$<br>
 */
class UXScrollBar extends UXComponent<UXScrollBarState>
{
	// {{{ public function new( size:UXSize, ?dir : UXScrollBarDirection )
	/**
	 * コンストラクタです。
	 * 引数で指定したDirectionのスクロールバーインスタンスを返します。デフォルトではHORIZONTALを指定します。
	 * @param size:スクロールバー自身のサイズです。
	 * @param dir:水平方向（HORIZONTAL）か垂直方向（VERTICAL）かを指定します。
	 */
	public function new( size:UXSize, ?dir : UXScrollBarDirection )
	{
		if (dir == null) dir = UXScrollBarDirection.HORIZONTAL;
		state = new UXScrollBarState(size,dir);
		state.target = this;
		ctrl = new UXController<UXScrollBarState>( state );
		super(ctrl);
		addUXChild(state.trac);
		addUXChild(state.thumb);
		ctrl.addInteraction( new UXScrollBarScrolledInteraction() );
		ctrl.addInteraction( new UXScrollBarScrollInteraction() );
		ctrl.addInteraction( new UXScrollBarStepScrollInteraction() );
		ctrl.addInteraction( new UXScrollBarPageScrollInteraction() );
		ctrl.addInteraction( new UXScrollBarWheelScrollInteraction() );
		ctrl.getInteraction("Scroll").addAct(state.acts.scroll());
		ctrl.getInteraction("StepScroll").addAct(state.acts.stepScroll());
		ctrl.getInteraction("PageScroll").addAct(state.acts.pageScroll());
		ctrl.getInteraction("Wheel").addReactEvent( UXMouseEvent.WHEEL );
		ctrl.getInteraction("Wheel").addAct(state.acts.wheelScroll());
	}
	// }}}
	// {{{ public function update( updator : UXScrollBarState -> Void ) : Void
	/**
	 * このコンポーネントの状態を直接変更するメソッドです。状態のどんな操作も可能になるので、
	 * このメソッドの使用には注意が必要です。
	 */
	public function update( updator : UXScrollBarState -> Void ) : Void
	{
		updator( state );
	}
	// }}}
}
// }}}

// {{{ class UXScrollBarScrolledInteraction extends UXInteraction<UXScrollBarState>
/**
 * UXScrollBarScrollInteraction クラス<br>
 * スクロールに対応するデフォルトインタラクションです。
 */
class UXScrollBarScrolledInteraction extends UXGeneralInteraction<UXScrollBarState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("Scrolled");
		setActSequentialMode(true);
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
// {{{ class UXScrollBarScrollInteraction extends UXInteraction<UXScrollBarState>
/**
 * UXScrollBarScrollInteraction クラス<br>
 * スクロールに対応するデフォルトインタラクションです。
 */
class UXScrollBarScrollInteraction extends UXGeneralInteraction<UXScrollBarState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("Scroll");
		setActSequentialMode(true);
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
// {{{ class UXScrollBarStepScrollInteraction extends UXInteraction<UXScrollBarState>
/**
 * UXScrollBarStepScrollInteraction クラス<br>
 * 一単位のスクロールに対応するデフォルトインタラクションです。
 */
class UXScrollBarStepScrollInteraction extends UXGeneralInteraction<UXScrollBarState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("StepScroll");
		setActSequentialMode(true);
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
// {{{ class UXScrollBarPageScrollInteraction extends UXInteraction<UXScrollBarState>
/**
 * UXScrollBarPageScrollInteraction クラス<br>
 * 一ページ分のスクロールに対応するデフォルトインタラクションです。
 */
class UXScrollBarPageScrollInteraction extends UXGeneralInteraction<UXScrollBarState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("PageScroll");
		setActSequentialMode(true);
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
// {{{ class UXScrollBarWheelScrollInteraction extends UXInteraction<UXScrollBarState>
/**
 * UXScrollBarWheelScrollInteraction クラス<br>
 * ホイールによるスクロールに対応するデフォルトインタラクションです。
 */
class UXScrollBarWheelScrollInteraction extends UXGeneralInteraction<UXScrollBarState>
{
	// {{{ public function new() : Void
	/**
	* コンストラクタ
	*/
	public function new() : Void
	{
		super("Wheel");
		setActSequentialMode(true);
		this.judge = function(s) {
			return s.enabled;
		}
	}

	// }}}
}
// }}}
